#include <iostream>
#include <cstring>
#include <unistd.h>

using namespace std;

int malloc_test(){
    char *m1 = (char *)malloc(0x10);
    printf("m1: %p \n", m1);

    char *m2 = (char *)malloc(0x10);
    printf("m2: %p \n", m2);

    char *m3 = (char *)malloc(0x20);
    printf("m3: %p \n", m3);

    char *m4 = (char *)malloc(0x30);
    printf("m4: %p \n", m4);

    char *m5 = (char *)malloc(0x60);
    printf("m5: %p \n", m5);


    printf("m1: %08x %08x\n", *((int *)m1 - 1), *((int *)m1 - 2));
    printf("m2: %08x %08x\n", *((int *)m2 - 1), *((int *)m2 - 2));
    printf("m3: %08x %08x\n", *((int *)m3 - 1), *((int *)m3 - 2));
    printf("m4: %08x %08x\n", *((int *)m4 - 1), *((int *)m4 - 2));
    printf("m5: %08x %08x\n", *((int *)m5 - 1), *((int *)m5 - 2));
 

    free(m3);   // 释放m3
    *((int *)m3 - 2) = 0xff;    // 修改大小标志
    printf("\n释放m3后，m3：%08x %08x\n", *((int *)m3 - 1), *((int *)m3 - 2));  // 并没有变化

    char *m6 = (char *)malloc(0x20);    // 申请和m3相同大小的内存
    printf("m6: %p \n", m6);
    printf("m6: %08x %08x\n", *((int *)m6 - 1), *((int *)m6 - 2));

    // *((int *)m3 - 2) = 0x31;
    free(m6);
    m6 = (char *)malloc(0x20);    // 申请和m3相同大小的内存
    printf("m6: %p \n", m6);
    printf("m6: %08x %08x\n", *((int *)m6 - 1), *((int *)m6 - 2));

}

void brk_test(){
    printf("堆结束地址：%p\n", sbrk(0));//sbrk(size); 以偏移方式设置堆的结束地址
    
    char *p = (char *)sbrk(0);        //偏移值为0，表示当前堆的结束地址
    brk(p + 4);                     //将堆的结束设置为 p + 4;相当于给p分配了4字节大小的空间
    printf("堆结束地址：%p\n", sbrk(0));
    
    
    p[0] = 0;
    p[3] = 3;
    p[6] = 1;       // 尽管只申请了4个char大小的位置，但是操作p[6]并不会发生错误
    p[4095] = 1;    // 正常
    // p[4096] = 1;    // Segmentation fault
    printf("%x, %x\n", p[0], p[3]);
    
    
    brk(p + 1);                     //收回3个char大小的空间
    printf("堆结束地址：%p\n", sbrk(0));
    p[3] = 1; // 正常


    brk(p);                         //恢复成最初的结束地址
    printf("堆结束地址：%p\n", sbrk(0));
    // p[0] = 1; // Segmentation fault
    
}

int main() {
    malloc_test();

    // brk_test();

    return 0;
}
